<html>

<head>
    <style>

    </style>
</head>

<body>

</body>
<script>
    // 创建svg的元素
    function makeSVG(tag, attrs) {
        var el = document.createElementNS('http://www.w3.org/2000/svg', tag);
        for (var k in attrs)
            el.setAttribute(k, attrs[k]);
        return el;
    }

    // svg节点
    var svg = makeSVG("svg", {
        "version": 1.1,
        "xmlns": "http://www.w3.org/2000/svg",
        "width": 500,
        "height": 500,
        
    });
    // rect宽
    var rect_wid = 50;
    // rect高
    var rect_hei = 400;
    // rect周长
    var rect_pm = (rect_wid + rect_hei) * 2;

    // 段的颜色
    var colors = [
        "#ff0000",
        "#00ff00",
        "#0000ff",
        "#ff00ff",
    ];
    // 一段的长度
    var dotted_line = 100;

    // 虚线间隔
    var dotted_offset = dotted_line * (colors.length - 1);//rect_pm - dotted_line;
    // 动画需要的rect
    var rectarr = [];

    // 圆半径
    var cir_radwid = 200;
    // 圆周长
    var cir_pm = 2 * Math.PI * cir_radwid;
    // colors共4段颜色，准备2次铺满
    var cir_line = cir_pm / (colors.length * 2);
    var cir_offset = cir_line * (colors.length - 1);

    var circlearr = [];
    // 一个自定义曲线
    var path_d = "M200 250,C250 300,450 300,490 250"
    var patharr = [];

    for (var i = 0; i < colors.length; i++) {
       
        // 一个标准的rect
        var one_rect = makeSVG("rect", {
            "x": 50,
            "y": 50,
            "width": rect_wid,
            "height": rect_hei,
            "fill": "none",
            "stroke-width": 10,
            "stroke": colors[i],
            "stroke-dasharray": dotted_line + " " + dotted_offset,
            "stroke-dashoffset": i * dotted_offset,
            "stroke-linecap": "square",//butt,square,round
            "id": "rect" + i
        });
        rectarr.push(one_rect);
    
        svg.appendChild(one_rect);

        // 一个标准圆
        var one_circle = makeSVG("circle", {
            "cx": 250,
            "cy": 250,
            "r": cir_radwid,
            "fill": "none",
            "stroke-width": 10,
            "stroke": colors[i],
            "stroke-dasharray": cir_line + " " + cir_offset,
            "stroke-dashoffset": i * cir_offset,
            "stroke-linecap": "round",//butt,square,round
            "id": "circle" + i
        })
        circlearr.push(one_circle);
        svg.appendChild(one_circle);
        // 一个自定义路径
        var one_path = makeSVG("path", {
            "d": path_d,
            "fill": "none",
            "stroke-width": 10,
            "stroke": colors[i],
            "stroke-dasharray": dotted_line + " " + dotted_offset,
            "stroke-dashoffset": i * dotted_offset,
            "stroke-linecap": "round",//butt,square,round
            "id": "path" + i
        });
        patharr.push(one_path);
        // 路径长度
        let path_leng = one_path.getTotalLength();

        svg.appendChild(one_path);
    }

    document.body.appendChild(svg);

    // 上帧时间，用来计算时间
    var lastframe = Date.now();
    // 运动的速度
    var rect1_offset = 0;
    // requestAnimationFrame的id
    var updateid = 1;
    // 帧循环
    var loop = () => {
        var ntime = Date.now();
        var passtime = ntime - lastframe;
        if (passtime > 30) {
            passtime = 30;
        }

        rect1_offset += passtime * 100 / 1000;

        for (var i1 = 0; i1 < rectarr.length; i1++) {
            var i1rect = rectarr[i1];
            i1rect.setAttribute("stroke-dashoffset", (rect1_offset + i1 * dotted_offset));
        }
        for (var i2 = 0; i2 < circlearr.length; i2++) {
            var i2circle = circlearr[i2];
            i2circle.setAttribute("stroke-dashoffset", (rect1_offset + i2 * cir_offset));
        }
        for (var i3 = 0; i3 < patharr.length; i3++) {
            var i3path = patharr[i3];
            i3path.setAttribute("stroke-dashoffset", (rect1_offset + i3 * dotted_offset));
        }
        updateid = requestAnimationFrame(loop);
    }

    // 清除帧循环
    var clearloop = () => {
        cancelAnimationFrame(updateid);
    }


    // 观察闭合路径，方形的首尾没有完美衔接，圆的首位连接的很好，导致这个问题的原因是，总长度没有正好分配给所有颜色，可调整每段长度，来实现正好铺满解决，一般图形可通过其周长的计算公式得到周长，path路径形式的可使用getTotalLength方法获得路径长度

    loop();
</script>

</html>